///////////////////
/// mkII - Core ///
///////////////////

#pragma once

// Core includes
#include "../mkMathDeclare.h"
#include "../../Math/Independent/mkMathConstants.h"

namespace mk
{
namespace Core
{
namespace Math
{

//!@ brief One-dimensional vector class
//!@ details Used in SSE calculations; not to be used as it is padded with an extra 12 bytes.
MK_MATH_VECTOR_CLASS(Vector1)
{
public:
// Constructors
MK_MATH_VECTOR1_CTOR( )                   MK_NOEXCEPT;
MK_MATH_VECTOR1_CTOR( real32 const v )    MK_NOEXCEPT;
MK_MATH_VECTOR1_CTOR( Vector128i   v )    MK_NOEXCEPT;
MK_MATH_VECTOR1_CTOR( Vector128r   v )    MK_NOEXCEPT;

// Assignment
operator real32   ( ) const               MK_NOEXCEPT;
Vector1& operator=( real32     v )        MK_NOEXCEPT;
Vector1& operator=( Vector128r v )        MK_NOEXCEPT;
Vector1& operator=( Vector128i v )        MK_NOEXCEPT;

private:
    union
    {
        Vector128r r;
        Vector128i i;
    };

}; // class Vector1

//! @brief Equality comparison operator.
bool operator==( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Inequality comparison operator.
bool operator!=( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Less-than comparison operator.
bool operator<( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Less-equal comparison operator.
bool operator<=( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Greater-than comparison operator.
bool operator>( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Greater-equal comparison operator.
bool operator>=( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar addition operator.
Vector1ConstValue operator+( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar subtraction operator.
Vector1ConstValue operator-( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar-scalar multiplication operator.
Vector1ConstValue operator*( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar-scalar division operator.
Vector1ConstValue operator/( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar addition assignment operator.
Vector1& operator+=( Vector1& a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar subtraction assignment operator.
Vector1& operator-=( Vector1& a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar-scalar multiplication assignment operator.
Vector1& operator*=( Vector1& a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar-scalar division assignment operator.
Vector1& operator/=( Vector1& a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Unary plus operator.
Vector1 operator+( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Unary minus operator.
Vector1 operator-( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Addition of two scalars.
Vector1ConstValue Add( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Subtraction of two scalars.
Vector1ConstValue Sub( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Multiplication of two scalars.
Vector1ConstValue Mul( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Division of two scalars.
Vector1ConstValue Div( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Multiplication-addition of three vectors.
Vector1ConstValue MAdd( Vector1ConstValue a, Vector1ConstValue b, Vector1ConstValue c ) MK_NOEXCEPT;

//! @brief Return the square root.
Vector1ConstValue Sqrt( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Square length of the vector.
Vector1ConstValue LengthSq( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Precise reciprocal of a scalar.
//! @warning Passing a zero length or very small vector \a v will produce a \b NaN.
Vector1ConstValue Reciprocal( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Approximate reciprocal of a scalar.
//! @details If hardware support for an estimate is available this function will use it, otherwise this
//! function is the same as the Reciprocal() function.
//! @warning Passing a zero length or very small vector \a v will produce a \b NaN.
Vector1ConstValue FastReciprocal( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Safe reciprocal of a scalar.
//! @details Get the reciprocal, if the reciprocal cannot be safely calculated (i.e. the value of the
//! vector is close or equal to zero) then return the safe reciprocal.
//! @param[in] v The vector to calculate the reciprocal of.
//! @param[in] r The 'safe' reciprocal to use if the reciprocal cannot be safely calculated.
Vector1ConstValue SafeReciprocal( Vector1ConstValue v, Vector1ConstValue r ) MK_NOEXCEPT;

//! @brief Precise reciprocal square root of a scalar.
//! @warning Passing a zero length or very small vector \a v will produce a \b NaN.
Vector1ConstValue ReciprocalSqrt( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Approximate reciprocal square root of a scalar.
//! @details If hardware support for an estimate is available this function will use it, otherwise this
//! function is the same as the ReciprocalSqrt() function.
//! @warning Passing a zero length or very small vector \a v will produce a \b NaN.
Vector1ConstValue FastReciprocalSqrt( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Safe reciprocal square root of a scalar.
//! @details Get the reciprocal square root, if the reciprocal of the square root of cannot be safely
//! calculated (i.e. the value of \a v is close or equal to zero) then return then the  'safe' reciprocal
//! \a r.
//! @param[in] v The vector to calculate the reciprocal square root of.
//! @param[in] r The 'safe' reciprocal square root to use if the reciprocal cannot be safely calculated.
Vector1ConstValue SafeReciprocalSqrt( Vector1ConstValue v, Vector1ConstValue r ) MK_NOEXCEPT;

//! @brief Absolute value.
Vector1ConstValue Abs( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Scalar modulo.
Vector1ConstValue Mod( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar minima.
Vector1ConstValue Min( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar maxima.
Vector1ConstValue Max( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Linear interpolation from \a a to \a b.
//! @param[in] a First value.
//! @param[in] b Second value.
//! @param[in] t The value to interpolate between \a a and \a b by.
//! @return \f$a + t(b-a)\f$
Vector1ConstValue Lerp( Vector1ConstValue a, Vector1ConstValue b, Vector1ConstValue t ) MK_NOEXCEPT;

//! @brief Clamp a scalar to a given range.
//! @param[in] v The vector to be clamped.
//! @param[in] min The minima to clamp \a v.
//! @param[in] max The maxima to clamp \a v.
Vector1ConstValue Clamp( Vector1ConstValue v, Vector1ConstValue min, Vector1ConstValue max ) MK_NOEXCEPT;

//! @brief Round downwards to the nearest integer value.
//! @return The rounded vector.
Vector1ConstValue Floor( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Round upwards to the nearest integer value.
//! @return The rounded vector.
Vector1ConstValue Ceil( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Round to the nearest integer value.
//! @return The rounded vector.
Vector1ConstValue Round( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Bitwise OR operation.
//! @return \f$a\text{ OR }b\f$
Vector1ConstValue Or( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Bitwise AND operation.
//! @return \f$a\text{ AND }b\f$
Vector1ConstValue And( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Bitwise XOR operation.
//! @return \f$a\text{ XOR }b\f$
Vector1ConstValue XOr( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Bitwise NOT operation.
//! @return \f$\text{ NOT }a\f$
Vector1ConstValue Not( Vector1ConstValue a ) MK_NOEXCEPT;

//! @brief Bitwise AND-NOT operation.
//! @return \f$a \text{ AND }(\text{NOT }b)\f$
Vector1ConstValue AndNot( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Bitwise selection from \a a and \a b.
//! @details Given a mask \a m and two vectors \a a and \a b, for all bits of mask \a m set to
//! \b true select the corresponding bits from \a a, select the bits from \a b otherwise.
//! @param[in] m The selection mask.
//! @param[in] a The first operand.
//! @param[in] b The second operand.
Vector1ConstValue Select( Vector1ConstValue m, Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Return the mask for the equals comparison of \a a and \a b.
Vector1ConstValue IsEqualMask( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Return the mask for the less than comparison of \a a and \a b.
Vector1ConstValue IsLessMask( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Return the mask for the less equal comparison of \a a and \a b.
Vector1ConstValue IsLessEqMask( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Return the mask for the greater than comparison of \a a and \a b.
Vector1ConstValue IsGreaterMask( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Return the mask for the greater equal comparison of \a a and \a b.
Vector1ConstValue IsGreaterEqMask( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Return \b true if the mask is \b true.
//! @return \b true if the mask is \b true.
bool IsTrue( Vector1ConstValue mask ) MK_NOEXCEPT;

//! @brief Return \b true if the mask is \b false.
//! @return \b true if the mask is \b false.
bool IsFalse( Vector1ConstValue mask ) MK_NOEXCEPT;

//! @brief Return \b true if the value of \a a is equal to \a b.
bool IsEqual( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Return \b true if the value of \a a is less than \a b.
bool IsLess( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Return \b true if the value of \a a is less or equal to \a b.
bool IsLessEq( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Return \b true if the value of \a a is greater than \a b.
bool IsGreater( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Return \b true if the value of \a a is greater or equal to \a b.
bool IsGreaterEq( Vector1ConstValue a, Vector1ConstValue b ) MK_NOEXCEPT;

//! @brief Is the value finite.
//! @return \b true if the value is finite, \b false otherwise.
bool IsFinite( Vector1ConstValue v ) MK_NOEXCEPT;

//! @brief Loads a Vector1 from a float's address.
Vector1ConstValue LoadVector1( real32 const* r ) MK_NOEXCEPT;

//! @brief Store a Vector1 given a destination address of a Real32.
//! @param[out] dst The address of a single float.
real32* StoreVector1( real32* dst, Vector1ConstValue v ) MK_NOEXCEPT;

} // namespace Math
} // namespace Core
} // namespace mk

#include "../../../Core/Math/Independent/mkVector1.inl"

